package notice

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
)

type EdmNoticer struct {
	config   *EdmConfig
	mergeMap map[string]*edmMessage
	m        sync.Mutex
}

type edmMessage struct {
	systemType string
	recipient  string
	subject    string
	content    string
}

func NewEdmNoticer(config *EdmConfig) *EdmNoticer {
	en := EdmNoticer{}
	if config == nil {
		en.config = NewEdmConfig()
	} else {
		en.config = config
	}
	if config.Interval > 0 {
		go func() {
			ticker := time.NewTicker(time.Duration(config.Interval) * time.Second)
			for {
				select {
				case <-ticker.C:
					en.m.Lock()
					for key, msg := range en.mergeMap {
						ret, err := en.Send(msg.systemType, msg.recipient, msg.subject, msg.content)
						log.Printf("edm send %s, content: %s, ret: %s, err: %v", msg.recipient, msg.content, ret, err)
						delete(en.mergeMap, key)
					}
					en.m.Unlock()
				}
			}
		}()
	}
	return &en
}

func (this *EdmNoticer) Send(systemType, recipient, subject, content string) (string, error) {
	payload := this.newPayload(systemType, recipient, subject, content)
	uri := this.newUri(payload)
	resp, err := http.Post(uri, "application/x-www-form-urlencoded", strings.NewReader(payload))
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func (this *EdmNoticer) SendMerge(key, systemType, recipient, subject, content string) {
	if this.mergeMap == nil {
		this.mergeMap = make(map[string]*edmMessage)
	}
	msg := &edmMessage{
		systemType: systemType,
		recipient:  recipient,
		subject:    subject,
		content:    content,
	}
	this.m.Lock()
	this.mergeMap[key] = msg
	this.m.Unlock()
}

func (this *EdmNoticer) newUri(data string) string {
	uri := url.Values{}
	uri.Add("protocol", "json")
	uri.Add("sessionId", "")
	uri.Add("user", this.config.User)
	sign := md5.Sum([]byte(uri.Get("protocol") + uri.Get("sessionId") + data + this.config.Password))
	uri.Add("sign", hex.EncodeToString(sign[:]))
	return fmt.Sprintf("%s?%s", this.config.Addr, uri.Encode())
}

func (this *EdmNoticer) newPayload(systemType, recipient, subject, content string) string {
	emdData := emdPostData{
		Version: "1.0",
		Class:   "RpcEdm_CrmSystemEdmQueue",
		Method:  "sendCrmMailQueue",
		Params: []string{
			recipient,
			systemType,
			subject,
			content,
		},
		Options: "",
		Id:      "0",
	}
	data, _ := json.Marshal(emdData)
	return string(data)
}

type emdPostData struct {
	Version string   `json:"version"`
	Class   string   `json:"class"`
	Method  string   `json:"method"`
	Params  []string `json:"params"`
	Options string   `json:"options"`
	Id      string   `json:"id"`
}
